package com.mf.config;

import io.github.heollhai.common.config.security.AuthorizationProperties;
import io.github.heollhai.common.config.security.RbacManager;
import io.github.heollhai.common.config.security.handler.AccessDeniedHandlerImpl;
import io.github.heollhai.common.config.security.handler.AuthenticationEntryPointImpl;
import io.github.heollhai.common.config.security.handler.TokenAuthenticationFilter;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;


/**
 * @Author: lmf
 * @Create: 2024/8/23 12:51
 * Description:
 */

@Configuration // 标识为配置类
public class SecurityConfig {
    /**
     * 配置权限属性 (白名单)
     */
    @Resource
    private AuthorizationProperties authorizationProperties;
    /**
     * 对权限验证失败需要调整登录页的自定义处理
     */
    @Resource
    private AuthenticationEntryPointImpl authenticationEntryPoint;

    /**
     * 配置权限管理器
     */
    @Resource
    private RbacManager rbacManager;
    /**
     * 配置权限不足自定义处理
     */
    @Resource
    private AccessDeniedHandlerImpl accessDeniedHandler;


    /**
     * 配置Security过滤器链
     *
     * @param http HttpSecurity对象，用于配置Web应用的Security保护措施
     * @return 配置好的Security过滤器链
     * @throws Exception 配置过程中可能抛出的异常
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // 开启授权保护
        http
                // 即关闭对所有请求的CSRF验证。
                .csrf(AbstractHttpConfigurer::disable)
                // 配置自定义的TokenAuthenticationFilter 添加对token验证验证用户，，并设置权限
                .addFilterBefore(tokenAuthenticationFilter(), LogoutFilter.class)
                // 配置会话管理策略为无状态  (前后端分离是无状态的，不需要session了，直接禁用)
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 配置请求的授权规则，允许所有用户访问/login路径，其他所有请求需要认证通过才能访问  /login
                .authorizeHttpRequests(auth ->
                                auth.requestMatchers(
                                                // 白名单接口运行不登录直接访问 (在配置文件中配置)
                                                authorizationProperties.getWhiteList().toArray(new String[0]))
                                        .permitAll()
                                        // 允许OPTIONS请求(预检接口)
                                        .requestMatchers(HttpMethod.OPTIONS, "/**")
                                        .permitAll()
                                        // 其余请求所有的都要登录
                                        .anyRequest()
                                        //  即用户必须提供有效的凭证可以访问所有资源
//                                .authenticated()
                                        //  自定义权限控制(通过存储在mysql中的配置进行对应的权限配置)
                                        .access(rbacManager)
                )
                // 异常处理
                .exceptionHandling(exception -> exception
                        // 默认调到登录页面  配置自定义的异常处理  拦截
                        .authenticationEntryPoint(authenticationEntryPoint)
                        // 权限不足自定义拦截处理
                        .accessDeniedHandler(accessDeniedHandler)
                )

        ;
        // 构建并返回配置好的Security过滤器链
        return http.build();
    }



    /**
     * 配置密码编码器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 配置自定义的TokenAuthenticationFilter 对token进行处理
     */
    @Bean
    public TokenAuthenticationFilter tokenAuthenticationFilter() {
        return new TokenAuthenticationFilter();
    }

    /**
     * AuthenticationManagerBuilder 用来，用于用户认证
     */
    @Bean
    public AuthenticationManager authenticationManager() {
        // 创建一个DaoAuthenticationProvider实例，用于自定义用户认证逻辑
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        // 设置密码编码器，确保认证提供者能够正确编码和验证密码
        provider.setPasswordEncoder(passwordEncoder());
        // 返回一个ProviderManager，管理并使用上述配置的认证提供者进行用户认证
        return new ProviderManager(provider);
    }
}
